#include "stdafx.h"
#include "SettingsManager.h"
#include "dllmain.h"
#include "AuthDlg.h"

const DWORD c_dwXmlVersion = 1;
const DWORD c_dwBuiltinToolbarCount = 9;

CPortalBrowserSettings::CPortalBrowserSettings():
	m_Flags(F_NONE),
	m_szDefaultSectionID(0),
	m_MagnetAction(MAGNET_DEFAULT),
	m_bCanLogin(false),
	m_hImageListLarge(NULL),
	m_hImageListSmall(NULL)
{
}

static inline void replace_all(std::wstring &s, LPCWSTR from, LPCWSTR to)
{
	size_t pos = 0, len = wcslen(from);// [!] PVS V303 The function 'lstrlen' is deprecated in the Win64 system. It is safer to use the 'wcslen' function.
	
	std::wstring sTo = to;
	if (sTo.find(from) != s.npos)
	{
		_ASSERT(FALSE);
		return;
	}
	
	while ((pos = s.find(from, pos)) != s.npos)
	{
		s.replace(pos, len, to);
	}
}

bool CPortalBrowserSettings::GetSearchString(SECTION_NODE const *pNode, LPCWSTR pszQuery, std::wstring &strURL, std::wstring &strCommand)
{
	bool bRet = false;
	strURL = m_strDefaultSearchURL + pNode->Section.strSearchURL;
	strCommand = pNode->Section.strSearchCommand;
	
	if (strURL.size())
	{
		std::wstring strQuery = UrlEncode(pszQuery, pNode->Section.Charset);
		
		replace_all(strURL, L"%QUERY%", strQuery.c_str());
		replace_all(strCommand, L"%QUERY%", strQuery.c_str());
		
		bRet = true;
	}
	
	return bRet;
}

bool CPortalBrowserSettings::GetLoginString(std::wstring &strLoginURL, std::wstring &strLoginCommand)
{
	strLoginURL = LoginURL;
	strLoginCommand = LoginCommand;
	
	return strLoginURL.size() != 0;
}

inline void AssignStr(std::wstring &str, LPCWSTR pszStr)
{
	if (pszStr)
		str = pszStr;
}

inline void AssignAppendStr(std::wstring &str, std::wstring &strBegin, LPCWSTR pszStr, bool bForceAssign = false)
{
	if (pszStr)
		str = strBegin + pszStr;
	else if (bForceAssign)
		str = strBegin;
}

static bool OpenXMLFile(XMLParser::XMLNode &xRootNode, std::wstring &strCurDir)
{
	bool bRet = false;
	XMLParser::XMLResults xRes;
	
	{
		strCurDir.resize(MAX_PATH);
		
		strCurDir.resize(GetModuleFileName(_AtlBaseModule.GetModuleInstance(), &strCurDir.at(0), (DWORD)strCurDir.size()) - 4);
		
		if (strCurDir.size() > 4 && _wcsicmp(&strCurDir.at(strCurDir.size() - 4), L"_x64") == 0)
			strCurDir.resize(strCurDir.size() - 4);
			
		strCurDir += L".xml";
		
		xRootNode = XMLParser::XMLNode::parseFile(strCurDir.c_str(), NULL, &xRes);
	}
	
	if (xRes.error == XMLParser::eXMLErrorNone && lstrcmpi(xRootNode.getName(), L"xml") == 0)
		xRootNode = xRootNode.getChildNode();
		
	if (xRes.error == XMLParser::eXMLErrorNone &&
	        lstrcmpi(xRootNode.getName(), L"PortalBrowser") == 0
	   )
	{
		bRet = true;
		
		strCurDir.resize(strCurDir.find_last_of(L'\\') + 1);
	}
	
	return bRet;
}

size_t CPortalBrowserSettings::EnumSectionFindURL(LPCWSTR pszURL, size_t dwURLLen, tSECTION_TREE const *pNode, size_t dwMatch, SECTION_NODE const **ppStruct)
{
	size_t ind = size_t(-1);
	size_t cur_ind = 0;
	for (tSECTION_TREE::const_iterator i = pNode->begin(); i != pNode->end(); ++i, cur_ind++)
	{
		if (i->Section.strURL.size() > dwMatch &&
		        i->Section.strURL.size() <= dwURLLen &&
		        _wcsnicmp(pszURL, i->Section.strURL.c_str(), i->Section.strURL.size()) == 0)
		{
			dwMatch = i->Section.strURL.size();
			*ppStruct = &(*i);
			ind = cur_ind;
		}
		
		size_t CurMatch = dwMatch;
		EnumSectionFindURL(pszURL, dwURLLen, &i->ChildNode, dwMatch, ppStruct);
		
		if (dwMatch > CurMatch)
			ind = cur_ind;
	}
	
	return ind;
}

size_t CPortalBrowserSettings::FindSectionByURL(LPCWSTR pszURL, SECTION_NODE const **ppStruct)
{
	size_t found_ind = size_t(-1);
	
	if (pszURL && *pszURL)
	{
		size_t dwURLLen = wcslen(pszURL);
		DWORD dwMatch = 0;
		
		found_ind = EnumSectionFindURL(pszURL, dwURLLen, &m_Section, dwMatch, ppStruct);
	}
	
	return found_ind;
}

void CPortalBrowserSettings::LoadSectionTree(std::wstring &strPortalURL, XMLParser::XMLNode const &xParameterNode, tSECTION_TREE &node, DefinedCharset DefaultCharset)
{
	SECTION_NODE snode;
	
	AssignStr(snode.Section.strName, xParameterNode.getAttribute(L"name"));
	
	if (xParameterNode.getAttribute(L"AbsolutePath") && lstrcmp(xParameterNode.getAttribute(L"AbsolutePath"), L"1") == 0)
		AssignStr(snode.Section.strURL, xParameterNode.getAttribute(L"URL"));
	else
		AssignAppendStr(snode.Section.strURL, strPortalURL, xParameterNode.getAttribute(L"URL"), true);
	AssignStr(snode.Section.strSearchCommand, xParameterNode.getAttribute(L"SearchCommand"));
	AssignStr(snode.Section.strSearchURL, xParameterNode.getAttribute(L"SearchURL"));
	AssignStr(snode.Section.strSearchName, xParameterNode.getAttribute(L"SearchName"));
	
	if (lstrcmpi(xParameterNode.getAttribute(L"Charset"), L"utf8") == 0)
		snode.Section.Charset = CH_UTF8;
	else
		snode.Section.Charset = DefaultCharset;
		
	LPCWSTR pszToolbarID = xParameterNode.getAttribute(L"LargeImageID");
	
	if (pszToolbarID)
	{
		if (lstrcmpi(pszToolbarID, L"Home") == 0)
			snode.Section.iToolbarID = 7;
		else if (lstrcmpi(pszToolbarID, L"Search") == 0)
			snode.Section.iToolbarID = 8;
		else
			snode.Section.iToolbarID = _wtoi(pszToolbarID) + c_dwBuiltinToolbarCount;
	}
	else
		snode.Section.iToolbarID = -1;
		
	LPCWSTR pszSearchbarID = xParameterNode.getAttribute(L"SmallImageID");
	
	if (pszSearchbarID)
		snode.Section.iSearchbarID = _wtoi(pszSearchbarID);
	else
		snode.Section.iSearchbarID = -1;
		
	node.push_back(snode);
	
	int i = 0;
	XMLParser::XMLNode xChildNode = xParameterNode.getChildNode(i);
	
	while (!xChildNode.isEmpty())
	{
		if (lstrcmpi(xChildNode.getName(), L"Section") == 0)
		{
			LoadSectionTree(strPortalURL, xChildNode, node.back().ChildNode, DefaultCharset);
		}
		
		xChildNode = xParameterNode.getChildNode(++i);
	}
}

void CPortalBrowserSettings::ParseFlag(XMLParser::XMLNode &xNode, LPCWSTR FlagName, int FlagVal, DWORD &dwFlags)
{
	LPCWSTR pszFlag = xNode.getAttribute(FlagName);
	if (pszFlag)
	{
		if (lstrcmpi(xNode.getAttribute(FlagName), L"1") == 0)
			dwFlags |= FlagVal;
		else
			dwFlags &= ~FlagVal;
	}
}

DWORD CPortalBrowserSettings::SetFlags(XMLParser::XMLNode &xNode, DWORD dwFlags)
{
	ParseFlag(xNode, L"DisableLoginDialog", F_DISABLE_AUTH_DLG, dwFlags);
	ParseFlag(xNode, L"DisableHubLogin", F_DISABLE_HUB_LOGIN, dwFlags);
	ParseFlag(xNode, L"DisableAutoUpdate", F_DISABLE_AUTOUPDATE, dwFlags);
	
	ParseFlag(xNode, L"AllowExternalLinks", F_ALLOW_EXTERNAL_LINKS, dwFlags);
	ParseFlag(xNode, L"DenyNewWnd", F_DENY_NEW_WND, dwFlags);
	ParseFlag(xNode, L"DenyExternalLinksNewWindow", F_DENY_EXTERNAL_LINKS_NEW_WND, dwFlags);
	ParseFlag(xNode, L"AllLinksInNewWnd", F_ALL_LINKS_IN_NEW_WND, dwFlags);
	
	ParseFlag(xNode, L"HostToolbarIconFirst", F_HOST_TOOLBAR_ICON_FIRST, dwFlags);
	ParseFlag(xNode, L"HostToolbarIconNone", F_HOST_TOOLBAR_ICON_NONE, dwFlags);
	ParseFlag(xNode, L"HostMenuNone", F_HOST_MENU_NONE, dwFlags);
	ParseFlag(xNode, L"EnableScriptDebugging", F_ENABLE_SCRIPT_DEBUGGING, dwFlags);
	ParseFlag(xNode, L"DisableToolbarFollowURL", F_DISABLE_TOOLBAR_FOLLOW_URL, dwFlags);
	
	ParseFlag(xNode, L"DisableToolbar", F_DISABLE_TOOLBAR, dwFlags);
	
	LPCWSTR pszShowRequestDumper = xNode.getAttribute(L"ShowRequestDumper");
	if (pszShowRequestDumper)
	{
		if (lstrcmpi(pszShowRequestDumper, L"1") == 0)
			dwFlags |= F_SHOW_REQUEST_DUMPER;
		else if (lstrcmpi(pszShowRequestDumper, L"2") == 0)
			dwFlags |= F_SHOW_REQUEST_DUMPER_ON_START | F_SHOW_REQUEST_DUMPER;
	}
	
	return dwFlags;
}

static void MakeImageList(HIMAGELIST &hImageListSRC, LPCWSTR pwcFileName)
{
	HIMAGELIST hImageList = ImageList_LoadImage(NULL, pwcFileName, 0, 0, CLR_NONE, IMAGE_BITMAP, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
	
	if (hImageListSRC)
	{
		if (hImageList)
		{
			const int iCount = ImageList_GetImageCount(hImageList);
			for (int i = 0; i < iCount; i++)
			{
				HICON hIcon = ImageList_GetIcon(hImageList, i, ILD_TRANSPARENT);
				ImageList_AddIcon(hImageListSRC, hIcon);
			}
			
			ImageList_Destroy(hImageList);
		}
	}
	else
		hImageListSRC = hImageList;
}

void CPortalBrowserSettings::ParsePortalSettings(XMLParser::XMLNode &xPortalNode, HINSTANCE hInstance, std::wstring &strCurDir, std::wstring &strPortalURL, std::wstring &strLoginUser, std::wstring &strLoginPassword, DefinedCharset DefaultCharset)
{
	int j = 0;
	XMLParser::XMLNode xParameterNode = xPortalNode.getChildNode(j);
	
	while (!xParameterNode.isEmpty())
	{
		if (lstrcmpi(xParameterNode.getName(), L"Login") == 0)
		{
			AssignAppendStr(m_strLoginURL, strPortalURL, xParameterNode.getAttribute(L"URL"));
			AssignStr(m_strLoginCommand, xParameterNode.getAttribute(L"Command"));
			AssignStr(strLoginUser, xParameterNode.getAttribute(L"user"));
			AssignStr(strLoginPassword, xParameterNode.getAttribute(L"password"));
		}
		
		else if (lstrcmpi(xParameterNode.getName(), L"Section") == 0)
		{
			LoadSectionTree(strPortalURL, xParameterNode, m_Section, DefaultCharset);
		}
		else if (lstrcmpi(xParameterNode.getName(), L"Images") == 0)
		{
			if (!m_hImageListLarge)
			{
				m_hImageListLarge = ImageList_LoadImage(hInstance, MAKEINTRESOURCE(IDI_BMP_TOOL_BAR), 0, 0, CLR_NONE, IMAGE_BITMAP, LR_CREATEDIBSECTION);
				_ASSERTE(c_dwBuiltinToolbarCount == ImageList_GetImageCount(m_hImageListLarge));
			}
			
			LPCWSTR pwcCustomToolbar = xParameterNode.getAttribute(L"CustomToolbar");
			if (pwcCustomToolbar)
			{
				size_t szCurDirLen = strCurDir.size();
				strCurDir += pwcCustomToolbar;
				m_hImageListLarge = ImageList_LoadImage(NULL, strCurDir.c_str(), 0, 0, CLR_NONE, IMAGE_BITMAP, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
				strCurDir.resize(szCurDirLen);
			}
			
			LPCWSTR pwcFileName = xParameterNode.getAttribute(L"Large");
			if (pwcFileName)
			{
				std::wstring str;
				AssignAppendStr(str, strCurDir, pwcFileName);
				MakeImageList(m_hImageListLarge, str.c_str());
			}
			
			pwcFileName = xParameterNode.getAttribute(L"Small");
			if (pwcFileName)
			{
				std::wstring str;
				AssignAppendStr(str, strCurDir, pwcFileName);
				MakeImageList(m_hImageListSmall, str.c_str());
			}
		}
		else if (lstrcmpi(xParameterNode.getName(), L"Flags") == 0)
		{
			m_Flags = SetFlags(xParameterNode, m_Flags);
		}
		else if (lstrcmpi(xParameterNode.getName(), L"Default") == 0)
		{
			LPCWSTR pid = xParameterNode.getAttribute(L"StartSection");
			if (pid)
				m_szDefaultSectionID = _wtoi(pid);
		}
		else if (lstrcmpi(xParameterNode.getName(), L"Magnet") == 0)
		{
			LPCWSTR pszMagnetAction = xParameterNode.getAttribute(L"action");
			
			m_MagnetAction = MAGNET_DEFAULT;
			if (pszMagnetAction)
			{
				if (lstrcmpi(pszMagnetAction, L"download") == 0)
					m_MagnetAction = MAGNET_DOWNLOAD;
				else if (lstrcmpi(pszMagnetAction, L"search") == 0)
					m_MagnetAction = MAGNET_SEARCH;
				else if (lstrcmpi(pszMagnetAction, L"ask") == 0)
					m_MagnetAction = MAGNET_ASK;
			}
		}
		
		j++;
		xParameterNode = xPortalNode.getChildNode(j);
	}
}

CPortalBrowserSettings::DefinedErrorValues CPortalBrowserSettings::LoadSettings(HINSTANCE hInstance, LPCWSTR pszPortalName, LPCWSTR pszLogin, LPCWSTR pszPassword)
{
	XMLParser::XMLNode xRootNode;
	
	DefinedErrorValues error = ERROR_PARSING;
	
	std::wstring strCurDir;
	
	if (OpenXMLFile(xRootNode, strCurDir))
	{
		int i = 0;
		XMLParser::XMLNode xPortalNode = xRootNode.getChildNode(L"Portal", i);
		
		std::wstring strLoginUser;
		std::wstring strLoginPassword;
		
		while (!xPortalNode.isEmpty())
		{
			if (lstrcmpi(xPortalNode.getAttribute(L"name"), pszPortalName) == 0)
			{
				// Found requested portal parameters
				
				LPCWSTR pszVersion = xPortalNode.getAttribute(L"XMLVersion");
				
				DWORD dwVer = 0;
				if (pszVersion)
					dwVer = _wtoi(pszVersion);
					
				if (dwVer < 1 || dwVer > c_dwXmlVersion)
				{
					error = ERROR_VERSION;
					break;
				}
				
				std::wstring strPortalURL;
				{
					LPCWSTR pszPortalURL = xPortalNode.getAttribute(L"URL");
					
					if (!pszPortalURL || *pszPortalURL == 0)
						continue;
						
					strPortalURL = pszPortalURL;
					
					// If started with '\' then it is local relative path to htm file
					if (strPortalURL[0] == L'\\')
						strPortalURL = strCurDir + &strPortalURL.at(1);
						
					if (strPortalURL[strPortalURL.size() - 1] != L'/')
						strPortalURL += '/';
				}
				
				AssignAppendStr(m_strDefaultSearchURL, strPortalURL, xPortalNode.getAttribute(L"SearchURL"), true);
				//AssignStr(m_strDefaultSearchCommand, xPortalNode.getAttribute(L"SearchCommand"));
				
				LPCWSTR pszCharset = xPortalNode.getAttribute(L"DefaultCharset");
				DefinedCharset DefaultCharset = CH_ANSI;
				if (pszCharset && lstrcmpi(pszCharset, L"utf8") == 0)
					DefaultCharset = CH_UTF8;
					
				ParsePortalSettings(xPortalNode, hInstance, strCurDir, strPortalURL, strLoginUser, strLoginPassword, DefaultCharset);
				
				XMLParser::XMLNode xUserDataNode = xPortalNode.getChildNode(L"UserData");
				
				// If exist UserData section -
				// overwrite main settings with user's
				if (!xUserDataNode.isEmpty())
					ParsePortalSettings(xUserDataNode, hInstance, strCurDir, strPortalURL, strLoginUser, strLoginPassword, DefaultCharset);
					
				error = m_Section.size() > 0 ? ERROR_NONE : ERROR_PARSING;
				
				if (error == ERROR_NONE)
				{
					if (!m_strLoginCommand.empty())
					{
						bool bWantLogin = m_strLoginCommand.find(L"%LOGIN%") != m_strLoginCommand.npos ||
						                  m_strLoginURL.find(L"%LOGIN%") != m_strLoginURL.npos;
						                  
						bool bWantPassword = m_strLoginCommand.find(L"%PASSWORD%") != m_strLoginCommand.npos ||
						                     m_strLoginURL.find(L"%PASSWORD%") != m_strLoginURL.npos;
						                     
						std::wstring strLogin;
						std::wstring strPassword;
						
						LPCWSTR pszWorkLogin = strLoginUser.empty() ? pszLogin : strLoginUser.c_str();
						LPCWSTR pszWorkPassword = strLoginPassword.empty() ? pszPassword : strLoginPassword.c_str();
						
						if (((!pszWorkLogin && bWantLogin) || (!pszWorkPassword && bWantPassword)) && (m_Flags & F_DISABLE_AUTH_DLG) == 0)
						{
							if (pszWorkLogin)
								strLogin = pszWorkLogin;
							if (pszWorkPassword)
								strPassword = pszWorkPassword;
								
								
							CAuthDlg dlg(bWantLogin ? &strLogin : NULL, bWantPassword ? &strPassword : NULL);
							dlg.DoModal();
							
							pszWorkLogin = strLogin.c_str();
							pszWorkPassword = strPassword.c_str();
						}
						
						if (bWantLogin && pszWorkLogin && *pszWorkLogin)
						{
							replace_all(m_strLoginCommand, L"%LOGIN%", pszWorkLogin);
							replace_all(m_strLoginURL, L"%LOGIN%", pszWorkLogin);
						}
						
						if (bWantPassword && pszWorkPassword && *pszWorkPassword)
						{
							replace_all(m_strLoginCommand, L"%PASSWORD%", pszWorkPassword);
							replace_all(m_strLoginURL, L"%PASSWORD%", pszWorkPassword);
						}
						
						if ((!bWantLogin || (pszWorkLogin && *pszWorkLogin)) && (!bWantPassword || (pszWorkPassword && *pszWorkPassword)))
							m_bCanLogin = true;
					}
					
					if (!m_hImageListLarge)
					{
						m_hImageListLarge = ImageList_LoadImage(hInstance, MAKEINTRESOURCE(IDI_BMP_TOOL_BAR), 0, 0, CLR_NONE, IMAGE_BITMAP, LR_CREATEDIBSECTION);
						_ASSERTE(c_dwBuiltinToolbarCount == ImageList_GetImageCount(m_hImageListLarge));
					}
				}
				
				break;
			}
			
			xPortalNode = xRootNode.getChildNode(L"Portal", ++i);
		}
	}
	else
		error = ERROR_PARSING;
		
	return error;
}

std::wstring CPortalBrowserSettings::UrlEncode(LPCWSTR pszString, DefinedCharset charset)
{
	std::string str;
	std::wstring strEncoded;
	size_t len = wcslen(pszString); // [!] PVS V303 The function 'lstrlen' is deprecated in the Win64 system. It is safer to use the 'wcslen' function.
	str.resize(len * sizeof(WCHAR));
	
	if (charset == CH_UTF8)
		str.resize(WideCharToMultiByte(CP_UTF8, 0, pszString, (int)len, &str.at(0), (int)str.size(), NULL, NULL));
	else
		str.resize(WideCharToMultiByte(CP_ACP, 0, pszString, (int)len, &str.at(0), (int)str.size(), NULL, NULL));
		
	strEncoded.resize(str.size() * 3);
	
	std::wstring::iterator j = strEncoded.begin();
	for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
	{
		wsprintf(&(*j), L"%%%02X", (unsigned char)*i);
		j += 3;
	}
	
	return strEncoded;
}

HBITMAP LoadImageFromList(LPCWSTR pwcFileName, size_t ind, bool bBuiltin)
{
	HBITMAP hBMP;
	
	if (bBuiltin)
	{
		hBMP = (HBITMAP)LoadImage(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCE(IDI_BMP_TOOL_BAR), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
		
#ifdef _DEBUG
		BITMAP bmp = {0};
		GetObject(hBMP, sizeof(bmp), &bmp);
		_ASSERTE(c_dwBuiltinToolbarCount == bmp.bmWidth / bmp.bmHeight);
#endif
	}
	else
		hBMP = (HBITMAP)LoadImage(NULL, pwcFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
		
	HBITMAP hRetBMP = NULL;
	
	if (hBMP)
	{
		BITMAP bm = {0};
		GetObject(hBMP, sizeof(bm), &bm);
		
		if (ind < size_t(bm.bmWidth / bm.bmHeight))
		{
			HDC hDC = GetDC(NULL);
			HDC hMemDC1 = CreateCompatibleDC(hDC);;
			HDC hMemDC2 = CreateCompatibleDC(hDC);;
			hRetBMP = CreateCompatibleBitmap(hDC, bm.bmHeight, bm.bmHeight);
			ReleaseDC(NULL, hDC);
			
			HBITMAP hOrgBMP1 = (HBITMAP)SelectObject(hMemDC1, hRetBMP);
			HBITMAP hOrgBMP2 = (HBITMAP)SelectObject(hMemDC2, hBMP);
			BitBlt(hMemDC1, 0, 0, bm.bmHeight, bm.bmHeight, hMemDC2, (int)(ind * bm.bmHeight), 0, SRCCOPY);
			
			SelectObject(hMemDC1, hOrgBMP1);
			SelectObject(hMemDC2, hOrgBMP2);
			
			DeleteDC(hMemDC1);
			DeleteDC(hMemDC2);
			
			DeleteObject(hBMP);
		}
	}
	
	return hRetBMP;
}

CPortalBrowserSettings::tPORTAL_LIST CPortalBrowserSettings::GetPortalsList()
{
	XMLParser::XMLNode xRootNode;
	
	tPORTAL_LIST PortalList;
	
	std::wstring strCurDir;
	
	if (OpenXMLFile(xRootNode, strCurDir))
	{
		int i = 0;
		XMLParser::XMLNode xPortalNode = xRootNode.getChildNode(L"Portal", i);
		
		std::wstring strLoginUser;
		std::wstring strLoginPassword;
		
		while (!xPortalNode.isEmpty())
		{
			PORTAL_INFO pi;
			
			RtlZeroMemory(&pi.Data, sizeof(pi.Data));
			pi.Data.dwSize = sizeof(pi.Data);
			
			AssignStr(pi.strName, xPortalNode.getAttribute(L"name"));
			AssignStr(pi.strAssociatedHubURL, xPortalNode.getAttribute(L"HubURL"));
			
			XMLParser::XMLNode xChildNode = xPortalNode.getChildNode(L"Images");
			
			if (!xChildNode.isEmpty())
			{
				LPCWSTR pwcSmallID = xChildNode.getAttribute(L"SmallImageID");
				LPCWSTR pwcSmall = pwcSmallID ? xChildNode.getAttribute(L"Small") : NULL;
				LPCWSTR pwcLargeID = xChildNode.getAttribute(L"LargeImageID");
				LPCWSTR pwcLarge = pwcLargeID ? xChildNode.getAttribute(L"Large") : NULL;
				
				size_t indLarge;
				bool bBuiltin = false;
				if (lstrcmpi(pwcLargeID, L"Home") == 0)
				{
					indLarge = 7;
					bBuiltin = true;
				}
				else if (lstrcmpi(pwcLargeID, L"Search") == 0)
				{
					indLarge = 8;
					bBuiltin = true;
				}
				else
					indLarge = _wtoi(pwcLargeID);
					
				size_t szCurPathLen = strCurDir.size();
				if (pwcLarge || bBuiltin)
				{
					if (bBuiltin || !pwcLarge)
					{
						LPCWSTR pwcCustomToolbar = xChildNode.getAttribute(L"CustomToolbar");
						if (pwcCustomToolbar)
							strCurDir += pwcCustomToolbar;
					}
					else
						strCurDir += pwcLarge;
						
					pi.hLargeBMP = LoadImageFromList(strCurDir.c_str(), indLarge, bBuiltin);
					strCurDir.resize(szCurPathLen);
				}
				else
					pi.hLargeBMP = NULL;
					
				if (pwcSmall)
				{
					size_t ind = _wtoi(pwcSmallID);
					strCurDir += pwcSmall;
					pi.hSmallBMP = LoadImageFromList(strCurDir.c_str(), ind, false);
					strCurDir.resize(szCurPathLen);
				}
				else
					pi.hSmallBMP = NULL;
			}
			
			// Fill main flags
			xChildNode = xPortalNode.getChildNode(L"Flags");
			if (!xChildNode.isEmpty())
			{
				DWORD dwFlags = SetFlags(xChildNode, F_NONE);
				
				if (dwFlags & F_HOST_TOOLBAR_ICON_NONE)
					pi.Data.dwFlags |= IPortalList::F_HOST_TOOLBAR_ICON_NONE;
				else if (dwFlags & F_HOST_TOOLBAR_ICON_FIRST)
					pi.Data.dwFlags |= IPortalList::F_HOST_TOOLBAR_ICON_FIRST;
					
				if (dwFlags & F_HOST_MENU_NONE)
					pi.Data.dwFlags |= IPortalList::F_HOST_MENU_NONE;
			}
			
			// Fill user flags
			xChildNode = xPortalNode.getChildNode(L"UserData");
			if (!xChildNode.isEmpty())
			{
				xChildNode = xChildNode.getChildNode(L"Flags");
				if (!xChildNode.isEmpty())
				{
					DWORD dwFlags = SetFlags(xChildNode, F_NONE);
					
					if (dwFlags & F_HOST_TOOLBAR_ICON_NONE)
						pi.Data.dwFlags |= IPortalList::F_HOST_TOOLBAR_ICON_NONE;
					else if (dwFlags & F_HOST_TOOLBAR_ICON_FIRST)
						pi.Data.dwFlags |= IPortalList::F_HOST_TOOLBAR_ICON_FIRST;
						
					if (dwFlags & F_HOST_MENU_NONE)
						pi.Data.dwFlags |= IPortalList::F_HOST_MENU_NONE;
				}
			}
			
			PortalList.push_back(pi);
			
			xPortalNode = xRootNode.getChildNode(L"Portal", ++i);
		}
	}
	
	return PortalList;
}